{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "b86ff9d6",
   "metadata": {},
   "source": [
    "# 单动作单智能体\n",
    "\n",
    "## **单个动作的单智能体**\n",
    "\n",
    "内容来自：\n",
    "[https://docs.deepwisdom.ai/v0.8/zh/guide/tutorials/agent\\_101.html](https://docs.deepwisdom.ai/v0.8/zh/guide/tutorials/agent%5C_101.html)\n",
    "\n",
    "## **使用现成的智能体**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "4c764e97",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2025-02-26 13:48:47.651 | INFO     | metagpt.const:get_metagpt_package_root:29 - Package root set to /tmp/code/wow-agent/notebooks\n",
      "2025-02-26 13:48:52.295 | INFO     | metagpt.roles.role:_act:391 - Alice(Product Manager): to do PrepareDocuments(PrepareDocuments)\n",
      "2025-02-26 13:48:52.506 | INFO     | metagpt.utils.file_repository:save:57 - save to: /tmp/code/wow-agent/notebooks/workspace/20250226134852/docs/requirement.txt\n"
     ]
    }
   ],
   "source": [
    "# 可导入任何角色，初始化它，用一个开始的消息运行它，完成！\n",
    "from metagpt.roles.product_manager import ProductManager\n",
    "prompt = f\"\"\"\n",
    "# Role：软件开发团队\n",
    "\n",
    "## Background :\n",
    "\n",
    "我是一个软件开发团队。\n",
    "现在要用html、js、vue3、element-plus开发一个刷题程序。\n",
    "刷题可以让人们对题目中涉及的知识点有更深的掌握。\n",
    "\n",
    "## Profile:\n",
    "- author: 黎伟\n",
    "- version: 0.1\n",
    "- language: 中文\n",
    "- description: 我是一软件开发团队。\n",
    "\n",
    "## Goals:\n",
    "- 用html、js、vue3、element-plus开发一个刷题程序的开发需求文档。\n",
    "\n",
    "## Constrains:\n",
    "1. 最后交付的程序是一个html单文件，不要有其他任何文件。\n",
    "2. 题目的题型至少包括两道判断题、两道选择题、两道填空题。\n",
    "3. 题目的内容与人工智能的agent基本理论相关。\n",
    "4. 刷题程序至少给出10道样例题目。\n",
    "5. 题目用列表的形式写到html文件的script部分。\n",
    "6. vue3、element-plus采用cdn的形式在html的header部分引入。\n",
    "\n",
    "## Skills:\n",
    "1. 具有强大的js语言开发能力\n",
    "2. 熟悉vue3、element-plus的使用\n",
    "3. 对人工智能的agent基本理论有较好理解\n",
    "4. 拥有排版审美, 会利用序号, 缩进, 分隔线和换行符等等来美化信息排版\n",
    "\n",
    "\n",
    "请结合上述要求完善刷题程序的开发需求文档。\n",
    "\"\"\"\n",
    "async def main():\n",
    "    role = ProductManager()\n",
    "    result = await role.run(prompt)\n",
    "    \n",
    "await main()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "64c2dc46",
   "metadata": {},
   "source": [
    "## **定制智能体**\n",
    "\n",
    "从实际使用的角度考虑，一个智能体要对我们有用，它必须具备哪些基本要素呢？从MetaGPT的观点来看，如果一个智能体能够执行某些动作（无论是由LLM驱动还是其他方式），它就具有一定的用途。简单来说，我们定义智能体应该具备哪些行为，为智能体配备这些能力，我们就拥有了一个简单可用的智能体！\n",
    "\n",
    "假设我们想用自然语言编写代码，并想让一个智能体为我们做这件事。让我们称这个智能体为 SimpleCoder，我们需要两个步骤来让它工作：\n",
    "\n",
    "1. 定义一个编写代码的动作\n",
    "2. 为智能体配备这个动作\n",
    "\n",
    "**定义动作**\n",
    "\n",
    "在 MetaGPT 中，类 Action 是动作的逻辑抽象。用户可以通过简单地调用 self.\\_aask 函数令 LLM 赋予这个动作能力，即这个函数将在底层调用 LLM api。\n",
    "\n",
    "我们可以尝试定义一个写唐诗的动作："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "b0b1532d",
   "metadata": {},
   "outputs": [],
   "source": [
    "from metagpt.actions import Action\n",
    "\n",
    "class TangPoem(Action):\n",
    "    PROMPT_TEMPLATE: str = \"\"\"\n",
    "    根据主题{msg}写一首五言绝句的唐诗。只返回生成诗的内容，不要有其他文字。\n",
    "    \"\"\"\n",
    "    async def run(self, msg: str):\n",
    "        prompt = self.PROMPT_TEMPLATE.format(msg = msg)\n",
    "        rsp = await self._aask(prompt)\n",
    "        return rsp"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "588b8734",
   "metadata": {},
   "source": [
    "先执行一下这个动作，看看效果如何？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "6713334b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "朝朝暮暮勤，步步汗如雨。\n",
      "心忧生计艰，梦回归故"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2025-02-26 13:52:55.153 | WARNING  | metagpt.utils.cost_manager:update_cost:49 - Model glm-4-flash not found in TOKEN_COSTS.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "里。\n",
      "朝朝暮暮勤，步步汗如雨。\n",
      "心忧生计艰，梦回归故里。\n"
     ]
    }
   ],
   "source": [
    "tangshi = TangPoem()\n",
    "rst = await tangshi.run('写一首表达上班很辛苦的唐诗')\n",
    "print(rst)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c162493b",
   "metadata": {},
   "source": [
    "怎么样？写诗的功力还不错吧？\n",
    "\n",
    "写诗写得好只能娱乐，我们接下来想要让智能体干活写代码！\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "b6a74e21",
   "metadata": {},
   "outputs": [],
   "source": [
    "from metagpt.actions import Action\n",
    "\n",
    "class SimpleWriteCode(Action):\n",
    "    PROMPT_TEMPLATE: str = \"\"\"\n",
    "    Write a python function that can {instruction} and provide two runnnable test cases.\n",
    "    Return ```python your_code_here ```with NO other texts,\n",
    "    your code:\n",
    "    \"\"\"\n",
    "\n",
    "    name: str = \"SimpleWriteCode\"\n",
    "\n",
    "    async def run(self, instruction: str):\n",
    "        prompt = self.PROMPT_TEMPLATE.format(instruction=instruction)\n",
    "\n",
    "        rsp = await self._aask(prompt)\n",
    "\n",
    "        code_text = SimpleWriteCode.parse_code(rsp)\n",
    "\n",
    "        return code_text\n",
    "\n",
    "    @staticmethod\n",
    "    def parse_code(rsp):\n",
    "        pattern = r\"```python(.*)```\"\n",
    "        match = re.search(pattern, rsp, re.DOTALL)\n",
    "        code_text = match.group(1) if match else rsp\n",
    "        return code_text"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "820e1a8e",
   "metadata": {},
   "source": [
    "## **定义角色**\n",
    "\n",
    "在 MetaGPT 中，Role 类是智能体的逻辑抽象。一个 Role 能执行特定的 Action，拥有记忆、思考并采用各种策略行动。基本上，它充当一个将所有这些组件联系在一起的凝聚实体。目前，让我们只关注一个执行动作的智能体，并看看如何定义一个最简单的 Role。\n",
    "\n",
    "在这个示例中，我们创建了一个 SimpleCoder，它能够根据人类的自然语言描述编写代码。步骤如下：\n",
    "\n",
    "1. 我们为其指定一个名称和配置文件。\n",
    "2. 我们使用 self.\\_init\\_action 函数为其配备期望的动作 SimpleWriteCode。\n",
    "3. 我们覆盖 \\_act 函数，其中包含智能体具体行动逻辑。我们写入，我们的智能体将从最新的记忆中获取人类指令，运行配备的动作，MetaGPT将其作为待办事项 (self.rc.todo) 在幕后处理，最后返回一个完整的消息。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "a1da10e5",
   "metadata": {},
   "outputs": [],
   "source": [
    "import re\n",
    "import os\n",
    "from metagpt.roles import Role\n",
    "from metagpt.schema import Message\n",
    "from metagpt.logs import logger\n",
    "\n",
    "class SimpleCoder(Role):\n",
    "    name: str = \"Alice\"\n",
    "    profile: str = \"SimpleCoder\"\n",
    "\n",
    "    def __init__(self, **kwargs):\n",
    "        super().__init__(**kwargs)\n",
    "        self.set_actions([SimpleWriteCode])\n",
    "\n",
    "    async def _act(self) -> Message:\n",
    "        logger.info(f\"{self._setting}: to do {self.rc.todo}({self.rc.todo.name})\")\n",
    "        todo = self.rc.todo  # todo will be SimpleWriteCode()\n",
    "\n",
    "        msg = self.get_memories(k=1)[0]  # find the most recent messages\n",
    "        code_text = await todo.run(msg.content)\n",
    "        msg = Message(content=code_text, role=self.profile, cause_by=type(todo))\n",
    "\n",
    "        return msg"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b75c9c44",
   "metadata": {},
   "source": [
    "## **运行你的角色**\n",
    "\n",
    "现在我们可以让我们的智能体开始工作，只需初始化它并使用一个起始消息运行它。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "75d750a0",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2025-02-26 13:55:35.506 | INFO     | __main__:main:4 - write a function that calculates the sum of a list\n",
      "2025-02-26 13:55:35.509 | INFO     | __main__:_act:16 - Alice(SimpleCoder): to do SimpleWriteCode(SimpleWriteCode)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "```python\n",
      "def sum_of_list(lst):\n",
      "    return sum(lst)\n",
      "\n",
      "# Test cases\n",
      "test_case_1 = [1, 2, 3, 4, 5]\n",
      "test_case_2 = [10, 20, 30, 40, 50]\n",
      "\n",
      "# Test case 1\n",
      "print(sum_of_list(test_case_1))  # Expected output: 15\n",
      "\n",
      "# Test case 2\n",
      "print(sum_of_list(test_case_2))  # Expected output: 150\n",
      "```"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2025-02-26 13:55:48.019 | WARNING  | metagpt.utils.cost_manager:update_cost:49 - Model glm-4-flash not found in TOKEN_COSTS.\n",
      "2025-02-26 13:55:48.022 | INFO     | __main__:main:6 - SimpleCoder: \n",
      "def sum_of_list(lst):\n",
      "    return sum(lst)\n",
      "\n",
      "# Test cases\n",
      "test_case_1 = [1, 2, 3, 4, 5]\n",
      "test_case_2 = [10, 20, 30, 40, 50]\n",
      "\n",
      "# Test case 1\n",
      "print(sum_of_list(test_case_1))  # Expected output: 15\n",
      "\n",
      "# Test case 2\n",
      "print(sum_of_list(test_case_2))  # Expected output: 150\n",
      "\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    }
   ],
   "source": [
    "async def main():\n",
    "    msg = \"write a function that calculates the sum of a list\"\n",
    "    role = SimpleCoder()\n",
    "    logger.info(msg)\n",
    "    result = await role.run(msg)\n",
    "    logger.info(result)\n",
    "    return result\n",
    "    \n",
    "        \n",
    "rtn = await main()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7f8f541e",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
